﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using AmazonGlacierGUI.Core;
using AmazonGlacierGUI.Core.Helpers.AmazonGlacier;
using AmazonGlacierGUI.Core.Infrastructure;
using AmazonGlacierGUI.Core.Model;
using AmazonGlacierGUI.UI.Infrastructure;
using AmazonGlacierGUI.UI.Infrastructure.MVVMFramework;
using GalaSoft.MvvmLight.Command;
using Raven.Database.Tasks;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;

namespace AmazonGlacierGUI.UI.ViewModels
{
    //20-Sep-2012 Priyan R
    public class DownloadArchiveFromAmazonInventoryViewModel : AppViewModelBase
    {
        public enum InventoryStatusEnum
        {
            None,
            CanRequest,
            Waiting,
            Error
        }


        public DownloadArchiveFromAmazonInventoryViewModel()
        {
            WireCommands();
            AddValidation(() => SaveToPath,
                          () =>
                          {
                              if (!Directory.Exists(SaveToPath))
                              {
                                  return new ValidationResultData("Path not exist");
                              }
                              return ValidationResultData.Success;
                          });
        }

        public void OnRefreshCommand()
        {
            LoadInventory();
        }

        public void OnRequestInventoryCommand()
        {
            IsLoading = true;
            RequestInventory((ex) =>
            {
                IsLoading = false;
                if (ex != null)
                {
                    InventoryStatusMessage =AppUtility.GetExceptionMessage(ex);
                    InventoryStatus = InventoryStatusEnum.CanRequest;
                    return;
                }
                InventoryStatus = InventoryStatusEnum.Waiting;
                InventoryStatusMessage = "Waiting for inventory request to complete...";
            });
        }

        private void OnDeleteCommand()
        {
            var archives = ArchiveDetails.Where(p => p.IsSelected).ToList();            
            UIHelper.ShowConfirm("Are you sure you want to delete " + archives.Count + " archive(s) selected",
                                 (v) =>
                                 {
                                     if (!v) return;
                                     IsLoading = true;
                                     DeleteArchives(archives.Select(p => p.ArchiveId).ToArray()
                                                    , (ex) =>
                                                    {
                                                        IsLoading = false;
                                                        if(ex!=null)
                                                        {
                                                            UIHelper.ShowError(AppUtility.GetExceptionMessage(ex),()=> { });
                                                            return;
                                                        }
                                                        foreach (var archive in archives)
                                                        {
                                                            ArchiveDetails.Remove(archive);
                                                        }
                                                        var temp = ArchiveDetails;
                                                        ArchiveDetails = null;
                                                        ArchiveDetails = temp;
                                                    });
                                 });
        }

        public void SetInventoryStatus()
        {
            if (Region == null || SelectedVault == null)
            {
                InventoryStatus = InventoryStatusEnum.None;
                ArchiveDetails = null;
                LastInventoryOn = null;
                InventoryStatusMessage = "";
                return;
            }
            if (_selectedVault.IsInventoryRequested == false && _selectedVault.LastInventoryOn == null)
            {
                LastInventoryOn = null;
                InventoryStatus = InventoryStatusEnum.CanRequest;
                InventoryStatusMessage = "Inventory not yet requested";
                return;
            }

            if (_selectedVault.LastInventoryOn != null)
            {
                IsLoading = true;
                GetCachedInventory((ex, res) =>
                {
                    IsLoading = false;
                    if (ex == null)
                    {
                        SetArchiveDetails(res);
                        InventoryStatus = InventoryStatusEnum.CanRequest;
                        LastInventoryOn = res.InventoryDate;
                    }
                    else
                    {
                        InventoryStatusMessage = AppUtility.GetExceptionMessage(ex);
                    }
                    if (_selectedVault.IsInventoryRequested)
                    {
                        InventoryStatus = InventoryStatusEnum.Waiting;
                        InventoryStatusMessage = "Waiting for inventory request to complete...";
                        LoadInventory();
                    }
                });
            }
            else if (_selectedVault.IsInventoryRequested)
            {
                InventoryStatus = InventoryStatusEnum.Waiting;
                InventoryStatusMessage = "Waiting for inventory request to complete...";
                LoadInventory();
            }
        }

        private void LoadInventory()
        {
            IsLoading = true;
            GetInventory((ex, res) =>
            {
                IsLoading = false;
                if (ex != null)
                {
                    InventoryStatus = InventoryStatusEnum.Error;
                    InventoryStatusMessage = "Error occured " + AppUtility.GetExceptionMessage(ex);
                }
                else if (res != null)
                {
                    InventoryStatus = InventoryStatusEnum.CanRequest;
                    LastInventoryOn = res.InventoryDate;
                    InventoryStatusMessage = "";
                    SetArchiveDetails(res);
                }
            });
        }

        private void SetArchiveDetails(VaultInventory inventory)
        {
            var archiveDetailsVM = new List<ArchiveDetailsVM>();
            foreach(var archiveDetail in inventory.ArchiveDetails)
            {
                archiveDetailsVM.Add(new ArchiveDetailsVM(this,archiveDetail));
            }
            ArchiveDetails = archiveDetailsVM;
        }

        private void OnResetCommand()
        {
            IsLoading = true;
            ResetInventory((ex) =>
            {
                IsLoading = false;
                if (ex != null) return;
                _selectedVault.IsInventoryRequested = false;
                InventoryStatus = InventoryStatusEnum.CanRequest;
                InventoryStatusMessage = "";
            });
        }

        public override void OnInit()
        {
            //IsLoading = true;
        }

        private void OnDownloadCommand()
        {
            if (!ValidateAll()) return;
            foreach (var archiveDetail in ArchiveDetails.Where(p => p.IsSelected))
            {
                if (!archiveDetail.ValidateAll()) return;
            }
            foreach (var archiveDetail in ArchiveDetails.Where(p => p.IsSelected))
            {
                var vm = new JobViewModel();
                vm.JobType = JobTypeEnum.Download;
                vm.DownloadArchiveId = archiveDetail.ArchiveId;
                vm.DownloadArchiveToPath = SaveToPath;
                vm.DownlodArchiveFileName = archiveDetail.SaveAsFileName;
                vm.VaultName = SelectedVault.VaultName;
                App.JobsVM.AddJob(vm);
            }
            Close();
        }

        private void OnBrowseVaultCommand()
        {
            if (!ValidateProperty(() => Region)) return;
            var vm = new VaultBrowserViewModel(Region.Value);
            UIHelper.ShowVaultBrowser(vm);
            if (vm.SelectedVault != null)
            {
                SelectedVault = vm.SelectedVault;
            }
        }

        private void OnBrowseFolderCommand()
        {
            UIHelper.ShowSelectFolderDialog(
                (path) => { SaveToPath = path; }, () => { });
        }

        private void WireCommands()
        {
            DownloadCommand = new RelayCommand(OnDownloadCommand,() =>ArchiveDetails!=null&&ArchiveDetails.Any(p => p.IsSelected));
            BrowseVaultCommand = new RelayCommand(OnBrowseVaultCommand);
            BrowseFolderCommand = new RelayCommand(OnBrowseFolderCommand);
            ResetCommand = new RelayCommand(OnResetCommand, () => CanReset);
            RefreshCommand = new RelayCommand(OnRefreshCommand, () => CanRefresh);
            RequestInventoryCommand = new RelayCommand(OnRequestInventoryCommand, () => CanRequestInventory);
            DeleteCommand = new RelayCommand(OnDeleteCommand, () =>ArchiveDetails!=null&&ArchiveDetails.Any(p => p.IsSelected));
        }


        private void RequestInventory(Action<Exception> onComplete)
        {
            Task.Factory.StartNew(
                () => AppContext.Current.GetServiceFactory().AppService.RequestInventory(SelectedVault.Id))
                .ContinueWith((t) =>
                {
                    if (t.Exception != null)
                        ExecuteOnUI(() => onComplete(t.Exception));
                    else
                    {
                        ExecuteOnUI(() => onComplete(null));
                    }
                });
        }

        private void GetCachedInventory(Action<Exception, VaultInventory> onComplete)
        {
            Task<VaultInventory>.Factory.StartNew(
                () => AppContext.Current.GetServiceFactory().AppService.GetCachedInventory(SelectedVault.Id))
                .ContinueWith((t) =>
                {
                    if (t.Exception != null)
                        ExecuteOnUI(() => onComplete(t.Exception, null));
                    else
                    {
                        ExecuteOnUI(() => onComplete(null, t.Result));
                    }
                });
        }

        private void GetInventory(Action<Exception, VaultInventory> onComplete)
        {
            Task<VaultInventory>.Factory.StartNew(
                () => AppContext.Current.GetServiceFactory().AppService.GetInventory(SelectedVault.Id))
                .ContinueWith((t) =>
                {
                    if (t.Exception != null)
                        ExecuteOnUI(() => onComplete(t.Exception, null));
                    else
                    {
                        ExecuteOnUI(() => onComplete(null, t.Result));
                    }
                });
        }

        private void ResetInventory(Action<Exception> onComplete)
        {
            Task.Factory.StartNew(
                () => AppContext.Current.GetServiceFactory().AppService.ResetInventoryRequest(SelectedVault.Id))
                .ContinueWith((t) => { ExecuteOnUI(() => onComplete(t.Exception)); });
        }
        private  void DeleteArchives(string[] archiveIds,Action<Exception> onComplete)
        {
            Task.Factory.StartNew(() =>
            {
                AppContext.Current.GetServiceFactory().AppService.DeleteArchives(
                    _selectedVault.Id, archiveIds);
            }).ContinueWith(t =>
            {
               ExecuteOnUI(()=>onComplete(t.Exception));
            });
        }

        private List<ArchiveDetailsVM> _archiveDetails;

        public List<ArchiveDetailsVM> ArchiveDetails
        {
            get { return _archiveDetails; }
            set
            {
                if (_archiveDetails != value)
                {
                    _archiveDetails = value;
                    RaisePropertyChanged(() => ArchiveDetails);
                    DeleteCommand.RaiseCanExecuteChanged();
                    DownloadCommand.RaiseCanExecuteChanged();
                }
            }
        }

        private string _saveToPath;

        public string SaveToPath
        {
            get { return _saveToPath; }
            set
            {
                if (_saveToPath != value)
                {
                    _saveToPath = value;
                    RaisePropertyChanged(() => SaveToPath);
                }
            }
        }

        private AmazonRegionEnum? _region;

        [Required]
        public AmazonRegionEnum? Region
        {
            get { return _region; }
            set
            {
                if (_region != value)
                {
                    _region = value;
                    RaisePropertyChanged(() => Region);
                    SelectedVault = null;
                    SetInventoryStatus();
                }
            }
        }

        private InventoryStatusEnum _inventoryStatus;

        public InventoryStatusEnum InventoryStatus
        {
            get { return _inventoryStatus; }
            set
            {
                if (_inventoryStatus != value)
                {
                    _inventoryStatus = value;
                    RaisePropertyChanged(() => InventoryStatus);
                    RaisePropertyChanged(() => CanRefresh);
                    RaisePropertyChanged(() => CanReset);
                    RaisePropertyChanged(() => CanRequestInventory);
                    ResetCommand.RaiseCanExecuteChanged();
                    RefreshCommand.RaiseCanExecuteChanged();
                    RequestInventoryCommand.RaiseCanExecuteChanged();
                }
            }
        }


        public bool CanRefresh
        {
            get
            {
                return (InventoryStatus == InventoryStatusEnum.Error)
                       || (InventoryStatus == InventoryStatusEnum.Waiting);
            }
        }

        public bool CanReset
        {
            get
            {
                return (InventoryStatus == InventoryStatusEnum.Error)
                       || (InventoryStatus == InventoryStatusEnum.Waiting);
            }
        }

        public bool CanRequestInventory
        {
            get
            {
                return
                    InventoryStatus == InventoryStatusEnum.CanRequest;
            }
        }

        private bool _isLoading;

        public bool IsLoading
        {
            get { return _isLoading; }
            set
            {
                if (_isLoading != value)
                {
                    _isLoading = value;
                    RaisePropertyChanged(() => IsLoading);
                }
            }
        }

        private DateTime? _lastInventoryOn;

        public DateTime? LastInventoryOn
        {
            get { return _lastInventoryOn; }
            set
            {
                if (_lastInventoryOn != value)
                {
                    _lastInventoryOn = value;
                    RaisePropertyChanged(() => LastInventoryOn);
                    if (value == null)
                        InventoryLastLoadedMessage = "";
                    else
                        InventoryLastLoadedMessage = "Inventory last loaded on " +
                                                     AppUtility.GetDateString(value.Value, true);
                }
            }
        }

    

        private string _inventoryStatusMessage;

        public string InventoryStatusMessage
        {
            get { return _inventoryStatusMessage; }
            set
            {
                if (_inventoryStatusMessage != value)
                {
                    _inventoryStatusMessage = value;
                    RaisePropertyChanged(() => InventoryStatusMessage);
                }
            }
        }

        private string _inventoryLastLoadedMessage;

        public string InventoryLastLoadedMessage
        {
            get { return _inventoryLastLoadedMessage; }
            set
            {
                if (_inventoryLastLoadedMessage != value)
                {
                    _inventoryLastLoadedMessage = value;
                    RaisePropertyChanged(() => InventoryLastLoadedMessage);
                }
            }
        }

        private VaultDetails _selectedVault;

        [Required]
        [Display(Name = "Vault")]
        public VaultDetails SelectedVault
        {
            get
            {
                return _selectedVault;
                ;
            }
            set
            {
                if (_selectedVault != value)
                {
                    _selectedVault = value;
                    RaisePropertyChanged(() => SelectedVault);
                    SetInventoryStatus();
                }
            }
        }

        public RelayCommand DownloadCommand { get; set; }
        public RelayCommand BrowseFolderCommand { get; set; }
        public RelayCommand BrowseVaultCommand { get; set; }
        public RelayCommand RequestInventoryCommand { get; set; }
        public RelayCommand ResetCommand { get; set; }
        public RelayCommand RefreshCommand { get; set; }
        public RelayCommand DeleteCommand { get; set; }

        public class ArchiveDetailsVM : AppViewModelBase
        {
            public ArchiveDetailsVM()
            {
                AddValidation(() => SaveAsFileName,
                              () =>
                              {
                                  if (string.IsNullOrWhiteSpace(SaveAsFileName) == false &&
                                      AppUtility.IsValidFileName(SaveAsFileName) == false)
                                  {
                                      return new ValidationResultData("Invalid file name");
                                  }
                                  return ValidationResultData.Success;
                              });
            }

            private DownloadArchiveFromAmazonInventoryViewModel _vm;
            public ArchiveDetailsVM(DownloadArchiveFromAmazonInventoryViewModel vm, ArchiveDetail detail)
                : this()
            {
                _vm = vm;
                ArchiveId = detail.ArchiveId;
                SaveAsFileName  = detail.Description;
                Size = detail.Size;
                UploadedOn = detail.CreatedOn;
                Description = detail.Description;
                EnableValidtion = true;
            }

            private string _archiveId;

            public string ArchiveId
            {
                get { return _archiveId; }
                set
                {
                    if (_archiveId != value)
                    {
                        _archiveId = value;
                        RaisePropertyChanged(() => ArchiveId);
                    }
                }
            }

         

            private string _saveAsFileName;

            [Required]
            public string SaveAsFileName
            {
                get { return _saveAsFileName; }
                set
                {
                    if (_saveAsFileName != value)
                    {
                        _saveAsFileName = value;
                        RaisePropertyChanged(() => SaveAsFileName);
                    }
                }
            }

            private bool _isSelected;

            public bool IsSelected
            {
                get { return _isSelected; }
                set
                {
                    if (_isSelected != value)
                    {
                        _isSelected = value;
                        RaisePropertyChanged(() => IsSelected);
                        _vm.DownloadCommand.RaiseCanExecuteChanged();
                        _vm.DeleteCommand.RaiseCanExecuteChanged();
                    }
                }
            }

            private DateTime _uploadedOn;

            public DateTime UploadedOn
            {
                get { return _uploadedOn; }
                set
                {
                    if (_uploadedOn != value)
                    {
                        _uploadedOn = value;
                        RaisePropertyChanged(() => UploadedOn);
                    }
                }
            }

            private long _size;

            public long Size
            {
                get { return _size; }
                set
                {
                    if (_size != value)
                    {
                        _size = value;
                        RaisePropertyChanged(() => Size);
                    }
                }
            }

            private string _description;

            public string Description
            {
                get { return _description; }
                set
                {
                    if (_description != value)
                    {
                        _description = value;
                        RaisePropertyChanged(() => Description);
                    }
                }
            }
        }
    }
}